package com.xiaoshuidi.cloud.module.report.xxljob;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.xiaoshuidi.cloud.framework.tenant.core.aop.TenantIgnore;
import com.xiaoshuidi.cloud.module.report.convert.finance.IncomeDetailConvert;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.IncomeDetailDayReportDO;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.IncomeDetailReportDO;
import com.xiaoshuidi.cloud.module.report.dal.mapper.report.IncomeDetailDayReportMapper;
import com.xiaoshuidi.cloud.module.report.service.finance.IncomeDetailReportService;
import com.xiaoshuidi.cloud.module.report.utils.DateUtils;
import com.xiaoshuidi.cloud.module.report.utils.ThreadPoolUtils;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * 收入明细处理 job 每天凌晨3:20跑一次
 * 需将汇总明细的数据进行再次汇总统计到月
 */
@Component
@Slf4j
public class IncomeDetailJob {

    @Resource
    private IncomeDetailReportService incomeDetailReportService;

    @Resource
    private IncomeDetailDayReportMapper incomeDetailDayReportMapper;

    @XxlJob("incomeDetailJob")
    @TenantIgnore
    public void execute() {
        //获取昨天所在当月所有的明细
        Integer minusDay = 1;
        String params = XxlJobHelper.getJobParam();
        if(StringUtils.isNotBlank(params)){
            try {
                minusDay = Integer.parseInt(params);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }
        final Integer minusDays = minusDay;
        String currentMonth = DateUtils.getYesterdayMonthAnI(minusDays);
        long totalNum = incomeDetailDayReportMapper.countDetailsInCurrentMonth(currentMonth);
        if (totalNum <= 1000) {
            //合同数<100直接一次处理
            List<IncomeDetailDayReportDO> list = incomeDetailDayReportMapper.selectDetailsInCurrentMonth(currentMonth);
            handlerDetails(list,minusDays);
        } else {
            //分200一批处理
            int pageNo = 0;
            int pageSize = 1000;
            List<IncomeDetailDayReportDO> list = null;
            int num = (int)totalNum/pageSize + 1 ;
            CountDownLatch latch = new CountDownLatch(num);
            do {
                int from = pageNo * pageSize;
                list = incomeDetailDayReportMapper.selectDetailsInCurrentMonthInTurn(currentMonth, from, pageSize);
                pageNo++;
                List<IncomeDetailDayReportDO> finalList = list;
                ThreadPoolUtils.poolExecutor.execute(()->{
                    handlerDetails(finalList,minusDays);
                    latch.countDown();
                });
            } while (list.size() == 1000);
            try {
                log.info("---------------处理收入明细完成-------------");
                latch.await();
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }
        }
    }

    private void handlerDetails(List<IncomeDetailDayReportDO> detailsList,int minusDays) {
        List<IncomeDetailReportDO> incomeDetailList = new ArrayList<>();
        for (IncomeDetailDayReportDO dayReportDO : detailsList) {
            List<IncomeDetailDayReportDO> dayList = incomeDetailDayReportMapper.selectDetailsInCurrentMonthByContractId(dayReportDO.getStatisticsMonth(), dayReportDO.getContractId());
            IncomeDetailDayReportDO reportDO = dayList.get(0);
            IncomeDetailReportDO incomeDetail = IncomeDetailConvert.INSTANCE.convertDetailDay2Month(reportDO);
            incomeDetail.setId(null);
            incomeDetail.setCurRentIn(dayList.stream().map(IncomeDetailDayReportDO::getCurRentIn).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setCurRentDisc(dayList.stream().map(IncomeDetailDayReportDO::getCurRentDisc).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setCurRentReduce(dayList.stream().map(IncomeDetailDayReportDO::getCurRentReduce).reduce(BigDecimal.ZERO, BigDecimal::add));
//            incomeDetail.setAccRentIn(dayList.stream().map(IncomeDetailDayReportDO::getAccRentIn).reduce(BigDecimal.ZERO, BigDecimal::add));
//            incomeDetail.setAccRentDisc(dayList.stream().map(IncomeDetailDayReportDO::getAccRentDisc).reduce(BigDecimal.ZERO, BigDecimal::add));
//            incomeDetail.setAccRentReduce(dayList.stream().map(IncomeDetailDayReportDO::getAccRentReduce).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setCurOtherIn(dayList.stream().map(IncomeDetailDayReportDO::getCurOtherIn).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setColdWaterFee(dayList.stream().map(IncomeDetailDayReportDO::getColdWaterFee).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setHotWaterFee(dayList.stream().map(IncomeDetailDayReportDO::getHotWaterFee).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setElectricFee(dayList.stream().map(IncomeDetailDayReportDO::getElectricFee).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setPropertyFee(dayList.stream().map(IncomeDetailDayReportDO::getPropertyFee).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setMaintenanceFee(dayList.stream().map(IncomeDetailDayReportDO::getMaintenanceFee).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setHouseTransferFee(dayList.stream().map(IncomeDetailDayReportDO::getHouseTransferFee).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setLiquidatedFee(dayList.stream().map(IncomeDetailDayReportDO::getLiquidatedFee).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setDelayFee(dayList.stream().map(IncomeDetailDayReportDO::getDelayFee).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setDamages(dayList.stream().map(IncomeDetailDayReportDO::getDamages).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setCurOtherDisc(dayList.stream().map(IncomeDetailDayReportDO::getCurOtherDisc).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetail.setCurOtherReduce(dayList.stream().map(IncomeDetailDayReportDO::getCurOtherReduce).reduce(BigDecimal.ZERO, BigDecimal::add));
//            incomeDetail.setAccOtherIn(dayList.stream().map(IncomeDetailDayReportDO::getAccOtherIn).reduce(BigDecimal.ZERO, BigDecimal::add));
//            incomeDetail.setAccOtherDisc(dayList.stream().map(IncomeDetailDayReportDO::getAccOtherDisc).reduce(BigDecimal.ZERO, BigDecimal::add));
//            incomeDetail.setAccOtherReduce(dayList.stream().map(IncomeDetailDayReportDO::getAccOtherReduce).reduce(BigDecimal.ZERO, BigDecimal::add));
            incomeDetailList.add(incomeDetail);
        }
        //查询当月是否已经生成过汇总明细收入
        List<Long> contractIds = incomeDetailList.stream().map(IncomeDetailReportDO::getContractId).collect(Collectors.toList());
        List<IncomeDetailReportDO> reportDOS = incomeDetailReportService.selectDetailsInCurrentMonthAndContractIds(DateUtils.getYesterdayMonthAnI(minusDays), contractIds);
        if (CollectionUtils.isEmpty(reportDOS)) {
            incomeDetailReportService.insertBatch(incomeDetailList);
        } else {
            //不为空
            incomeDetailList.forEach(e -> {
                reportDOS.forEach(report -> {
                    if (e.getContractId().equals(report.getContractId())) {
                        e.setId(report.getId());
                    }
                });
            });
            List<IncomeDetailReportDO> updateList = incomeDetailList.stream().filter(e -> e.getId() != null).collect(Collectors.toList());
            List<IncomeDetailReportDO> insertList = incomeDetailList.stream().filter(e -> e.getId() == null).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(updateList)) {
                incomeDetailReportService.updateBatch(updateList);
            }
            if (CollectionUtils.isNotEmpty(insertList)) {
                incomeDetailReportService.insertBatch(insertList);
            }
        }
    }


}